package com.iwhalecloud.uncc.dao.impl;


import com.ctg.itrdc.cache.pool.CtgJedisPool;
import com.ctg.itrdc.cache.pool.CtgJedisPoolConfig;
import com.ctg.itrdc.cache.pool.ProxyJedis;
import com.iwhalecloud.uncc.dao.RedisClusterDao;
import com.iwhalecloud.uncc.model.RedisConfig;
import com.iwhalecloud.uncc.utils.Byte2ObjectUtil;
import com.iwhalecloud.uncc.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisPoolConfig;

import java.io.StringReader;
import java.lang.reflect.Method;
import java.text.NumberFormat;
import java.util.*;

@Slf4j
public class CtgClusterDaoImpl implements RedisClusterDao {
    private static final int EXPIRE_DAY = 7;

    private CtgJedisPool ctgJedisPool;

    @Override
    public void init(RedisConfig redisConfig) {
        try {
            log.info("************ctg redis template load start************");
            String[] hostPorts = redisConfig.getHostPort().split(",");
            String userName = redisConfig.getUsername();
            String password = redisConfig.getPwd();
            int database = redisConfig.getDb();
            long period = redisConfig.getPeriod();
            int monitorTimeout = redisConfig.getMonitorTimeout();
            String poolProperties = redisConfig.getPoolProperties().replaceAll("@@", "\n");

            // 接入机的ip和端口号
            List<HostAndPort> hostAndPortList = new ArrayList<HostAndPort>();
            for (String str : hostPorts) {
                String host = str.split(":")[0];
                Integer port = Integer.parseInt(str.split(":")[1]);
                HostAndPort hostAndPort = new HostAndPort(host, port);
                hostAndPortList.add(hostAndPort);
            }

            JedisPoolConfig poolConfig = new JedisPoolConfig();
            final Properties pp = new Properties();
            pp.load(new StringReader(poolProperties));
            for (Enumeration<Object> enumeration = pp.keys(); enumeration.hasMoreElements(); ) {
                String key = enumeration.nextElement().toString();
                Method[] methods = GenericObjectPoolConfig.class.getMethods();
                String methodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1);
                for (Method m : methods) {
                    if (methodName.equals(m.getName())) {
                        Object value = StringUtil.castStringToX(m.getParameterTypes()[0], pp.getProperty(key));
                        m.invoke(poolConfig, value);
                        break;
                    }
                }
            }

            CtgJedisPoolConfig ctgJedisPoolConfig = new CtgJedisPoolConfig(hostAndPortList);
            ctgJedisPoolConfig.setDatabase(database).setPassword(userName + "#" + password).setPeriod(period)
                    .setMonitorTimeout(monitorTimeout).setMonitorLog(false).setPoolConfig(poolConfig)
                    .setMonitorSwitch(false);
            ctgJedisPool = new CtgJedisPool(ctgJedisPoolConfig);

            log.info("Redis ctg template load  completely");
        } catch (Exception e) {
            log.error("redis client init error " + ExceptionUtils.getStackTrace(e));
        }
    }

    public void closeProxyJedis(ProxyJedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

    @Override
    public void set(String key, Object value) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            proxyJedis.set(key.getBytes(), Byte2ObjectUtil.objectToByte(value));
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
    }


    @Override
    public void setEx(String key, Object value) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            proxyJedis.setex(key.getBytes(), EXPIRE_DAY * 24 * 60 * 60, Byte2ObjectUtil.objectToByte(value));
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
    }

    @Override
    public void setEx(String key, Object value, int seconds) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            proxyJedis.setex(key.getBytes(), seconds, Byte2ObjectUtil.objectToByte(value));
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
    }

    @Override
    public Object get(String key) {
        ProxyJedis proxyJedis = null;
        Object result = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            byte[] bytes = proxyJedis.get(key.getBytes());
            result = Byte2ObjectUtil.byteToObject(bytes);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Boolean setNX(String key, Object value) {
        ProxyJedis proxyJedis = null;
        Boolean result = false;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.setnx(key.getBytes(), Byte2ObjectUtil.objectToByte(value)) > 0;
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Map<String, String> getHashByKey(String key) {
        ProxyJedis proxyJedis = null;
        Map<String, String> result = new HashMap<>();
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.hgetAll(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public void lPush(String key, String value) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            proxyJedis.lpush(key, value);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
    }

    @Override
    public String rPop(String key) {
        ProxyJedis proxyJedis = null;
        String result = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.rpop(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Boolean hSet(String key, String field, String value) {
        ProxyJedis proxyJedis = null;
        Boolean result = false;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.hset(key, field, value) > 0;
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public String hGet(String key, String field) {
        ProxyJedis proxyJedis = null;
        String result = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.hget(key, field);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Long hdel(String key, String field) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            return proxyJedis.hdel(key, field);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return 0L;
    }

    @Override
    public Long del(String key) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
           return proxyJedis.del(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return -1L;
    }

    @Override
    public void rPush(String key, String value) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            proxyJedis.rpush(key, value);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
    }

    @Override
    public String lPop(String key) {
        ProxyJedis proxyJedis = null;
        String result = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.lpop(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public List<String> lRange(String key, long start, long end) {
        ProxyJedis proxyJedis = null;
        List<String> result = new ArrayList<>();
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.lrange(key, start, end);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Long lLen(String key) {
        ProxyJedis proxyJedis = null;
        Long result = 0L;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.llen(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Long sRem(String key, String value) {
        ProxyJedis proxyJedis = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            return proxyJedis.srem(key, value);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return null;
    }

    @Override
    public Long incr(String key) {
        ProxyJedis proxyJedis = null;
        Long result = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.incr(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public boolean exists(String key) {
        ProxyJedis proxyJedis = null;
        boolean result = false;
        try {
            proxyJedis = ctgJedisPool.getResource();
            result = proxyJedis.exists(key);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

    @Override
    public Number getNumber(String key) {
        ProxyJedis proxyJedis = null;
        Number result = null;
        try {
            proxyJedis = ctgJedisPool.getResource();
            byte[] value = proxyJedis.get(key.getBytes());
            if (value != null) {
                String s = new String(value);
                result = NumberFormat.getInstance().parse(s);
            }
        } catch (Exception e) {
            log.info(e.getMessage(), e);
        } finally {
            closeProxyJedis(proxyJedis);
        }
        return result;
    }

	@Override
	public void setExHasExpire(String key, Object value, long expireTime) {
		// TODO Auto-generated method stub
		
	}

    @Override
    public void lock(String lock) {

    }

    @Override
    public void unLock(String lock) {

    }

    @Override
    public boolean setNxAndExpire(String key, Object value, long expireTime) {
        // TODO Auto-generated method stub
        return false;
    }
}